package event;

import org.junit.Test;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.context.event.EventListenerMethodProcessor;

/**
 * EventListenerMethodProcessor 实现了 {@link SmartInitializingSingleton}
 * 在所有单例初始化完成后回调 afterSingletonsInstantiated() 并注册事件监听器
 *
 * {@link EventListenerMethodProcessor#afterSingletonsInstantiated()}
 *
 * 实现：{@link EventListenerMethodProcessor#processBean(String, Class)}
 *
 * @author jackcfan
 * @date 2021/9/30
 */
@EnableAsync
public class ApplicationListenerTest implements ApplicationEventPublisherAware {
    // ApplicationEventPublisher 只能由依赖注入，不可依赖查找
    ApplicationEventPublisher applicationEventPublisher;

    // 发布事件
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
        applicationEventPublisher.publishEvent(new ApplicationEvent("hello"){});

        /**
         * 发布任意类型的事件
         * @see org.springframework.context.PayloadApplicationEvent
         * */
        applicationEventPublisher.publishEvent("hello payload");
    }

    // 泛型指定注册的类型
    static class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent>{
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            System.out.println("MyApplicationListener 接口接收到事件:"+event);
        }
    }

    @Test
    public void annotationEventListener() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(ApplicationListenerTest.class);

        // 基于接口的事件注册
        // ApplicationListener 会监听到多个事件
        applicationContext.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("接口接收到事件:"+event);
            }
        });

        /**
         * 基于注解的事件注册
         * 注册 {@link #onApplicationEvent(ApplicationEvent)}
         * */

        applicationContext.refresh();   // ContextRefreshedEvent
        applicationContext.stop();      // ContextStoppedEvent
    }

    @Test
    public void genericEventListener() {
        GenericApplicationContext applicationContext = new GenericApplicationContext();

        // 基于接口的事件注册
        // ApplicationListener 会监听到多个事件
        applicationContext.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("接口接收到事件:"+event);
            }
        });

        applicationContext.addApplicationListener(new MyApplicationListener());

        applicationContext.refresh();   // ContextRefreshedEvent
        applicationContext.stop();      // ContextStoppedEvent
    }

    // 包含多个事件监听
    @EventListener
    @Order(1)
    public void onApplicationEvent(ApplicationEvent event){
        System.out.println(Thread.currentThread().getName()+">@EventListener onApplicationEvent 接收到事件:"+event);
    }

    @Order(2)
    @EventListener
    public void onApplicationEvent2(ApplicationEvent event){
        System.out.println(Thread.currentThread().getName()+">@EventListener onApplicationEvent2 接收到事件:"+event);
    }

    // 具体的 ContextStoppedEvent 事件监听
    @EventListener
    @Async // 异步执行
    public void onContextClosedEvent(ContextStoppedEvent event){
        System.out.println(Thread.currentThread().getName()+">@EventListener ContextStoppedEvent 接收到事件:"+event);
    }
}
